package elephant.servers.gameserver.service;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author icecooly
 *
 */
public class GameServiceManager {
	//
	private static Logger logger=LoggerFactory.getLogger(GameServiceManager.class);
	//
	private Map<String,GameService> gameServiceMap;
	private Map<String,MethodInfo> methodMap;
	
	public GameServiceManager(){
		gameServiceMap=new HashMap<>();
		methodMap=new HashMap<>();
	}
	
	public void registerService(GameService gs){
		Class<?> c=gs.getClass();
		String name=c.getSimpleName();
		if(gameServiceMap.containsKey(name)){
			throw new IllegalArgumentException("object with name:"+name
					+" already exists."); 
		}
		if(logger.isInfoEnabled()){
			logger.info("register service "+name);
		}
		gameServiceMap.put(name,gs);
		registerMethod(c);
	}
	
	private void registerMethod(Class<?> c){
		for(Method m:c.getDeclaredMethods()){
			if(!Modifier.isPublic(m.getModifiers())){
				continue;
			}
			if(!m.getReturnType().equals(Void.TYPE)){
				continue;
			}
			Class<?> parameterTypes[]=m.getParameterTypes();
			if(parameterTypes==null||parameterTypes.length<1){
				continue;
			}
			if(!parameterTypes[0].equals(ServiceContext.class)){
				continue;
			}
			if(!checkParameterAnnotation(m)){
				continue;
			}
			String serviceId=c.getSimpleName()+"."+m.getName();
			if(logger.isInfoEnabled()){
				logger.info("register method "+serviceId);
			}
			//success
			boolean disableResponse=m.getAnnotation(NoResponse.class)!=null;
			boolean syncOnSession=m.getAnnotation(SyncOnSession.class)!=null;
			MethodInfo method=new MethodInfo(m,disableResponse,syncOnSession);
			methodMap.put(serviceId, method);
		}
	}

	private boolean checkParameterAnnotation(Method m){
		Class<?>types[]=m.getParameterTypes();
		for(int i=1;i<types.length;i++){
			Class<?>type=types[i];
			if(!type.equals(String.class)&&
					!type.equals(Integer.class)&&
					!type.equals(Double.class)&&
					!type.equals(Float.class)&&
					!type.equals(Long.class)&&
					!type.equals(Boolean.class)){
				logger.warn(m.getDeclaringClass().getSimpleName()+"."+m.getName()
						+"/parameter must be String/Integer/Double/Float/Long/Boolean");
				return false;
			}
		}
		return true;
	}
	//
	public GameService getService(String serviceClassName){
		logger.debug("getService:"+serviceClassName+","+gameServiceMap);
		return gameServiceMap.get(serviceClassName);
	}
	//
	public MethodInfo getMethod(String serviceId){
		logger.debug("getMethod "+serviceId+","+methodMap);
		return methodMap.get(serviceId);
	}
	//
	public Map<String, MethodInfo> getMethodMap() {
		return methodMap;
	}
	
}
